package com.hzy.service.document;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCConnectOptions;
import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.PoolOptions;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.Tuple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class SqliteDocumentVerticle extends AbstractVerticle implements DocumentVerticle {

    private static final Logger LOGGER = LoggerFactory.getLogger(SqliteDocumentVerticle.class);


    private JDBCPool sqlitePool;

    @Override
    public void start(Promise<Void> startPromise) {
        JsonObject config = (JsonObject) vertx.sharedData().getLocalMap("config").get("appConfig");

        // SQLite 数据库配置
        JsonObject dbConfig = config.getJsonObject("database");
        // SQLite 连接字符串通常指向一个文件，例如 "jdbc:sqlite:./data/documents.db"
        // 确保你的项目根目录下有 'data' 文件夹，或者根据实际路径调整
        String dbPath = dbConfig.getString("path", "./data/documents.db");

        JDBCConnectOptions connectOptions = new JDBCConnectOptions()
                .setJdbcUrl("jdbc:sqlite:" + dbPath);

        PoolOptions poolOptions = new PoolOptions().setMaxSize(dbConfig.getInteger("poolSize", 10));
        sqlitePool = JDBCPool.pool(vertx, connectOptions, poolOptions);

        initializeDatabase(startPromise);

        registerServiceConsumer(vertx, ADD_DOCUMENT_ADDRESS, this::addDocument);
        registerServiceConsumer(vertx, GET_DOCUMENT_BY_ID_ADDRESS, this::getDocumentById);
        registerServiceConsumer(vertx, SEARCH_DOCUMENTS_ADDRESS, this::searchDocuments);
    }

    private void initializeDatabase(Promise<Void> startPromise) {
        // 1. 初始化 SQLite 文档主表 (用于存储完整文档内容)
        sqlitePool.query("CREATE TABLE IF NOT EXISTS documents (" +
                        "id TEXT PRIMARY KEY," +
                        "title TEXT NOT NULL," +
                        "content TEXT NOT NULL," +
                        "created_at DATETIME DEFAULT CURRENT_TIMESTAMP)")
                .execute()
                .compose(result -> {
                    LOGGER.info("SQLite 'documents' table ensured.");
                    // 2. 初始化 FTS5 虚拟表 (用于全文检索)
                    // 注意：这里 id 也是一个字段，方便 FTS5 检索后通过 id 关联到主表
                    return sqlitePool.query("CREATE VIRTUAL TABLE IF NOT EXISTS documents_fts USING fts5(id, title, content);")
                            .execute();
                })
                .onSuccess(result -> {
                    LOGGER.info("SQLite 'documents_fts' FTS5 table ensured.");
                    LOGGER.info("DocumentVerticle deployed successfully.");
                    startPromise.complete();
                })
                .onFailure(throwable -> {
                    LOGGER.error("Failed to initialize SQLite database: {}", throwable.getMessage());
                    startPromise.fail(throwable);
                });
    }

    /**
     * 将文档添加到 SQLite 数据库并索引到 FTS5。
     *
     * @param document 包含 title 和 content 的 JsonObject
     * @return 包含新文档 ID 和状态的 Promise
     */
    private Promise<JsonObject> addDocument(JsonObject document) {
        Promise<JsonObject> promise = Promise.promise();
        String id = UUID.randomUUID().toString();
        String title = document.getString("title");
        String content = document.getString("content");

        if (title == null || content == null) {
            promise.fail("Document must have 'title' and 'content'.");
            return promise;
        }

        // 1. 存储到 SQLite 主表
        sqlitePool.preparedQuery("INSERT INTO documents (id, title, content) VALUES (?, ?, ?)")
                .execute(Tuple.of(id, title, content))
                .compose(pgResult -> {
                    // 2. 索引到 FTS5 虚拟表 (FTS5 的插入是直接插入数据)
                    return sqlitePool.preparedQuery("INSERT INTO documents_fts (id, title, content) VALUES (?, ?, ?)")
                            .execute(Tuple.of(id, title, content));
                })
                .onSuccess(ftsResult -> {
                    LOGGER.info("Document '{}' added and indexed successfully.", id);
                    promise.complete(new JsonObject().put("id", id).put("status", "indexed"));
                })
                .onFailure(throwable -> {
                    LOGGER.error("Failed to add or index document: {}", throwable.getMessage());
                    promise.fail("Failed to add or index document: " + throwable.getMessage());
                });

        return promise;
    }

    /**
     * 从 SQLite 数据库根据 ID 获取文档。
     *
     * @param docId 文档ID
     * @return 包含文档内容的 Promise
     */
    private Promise<JsonObject> getDocumentById(String docId) {
        Promise<JsonObject> promise = Promise.promise();
        sqlitePool.preparedQuery("SELECT id, title, content FROM documents WHERE id = ?")
                .execute(Tuple.of(docId))
                .onSuccess(rowSet -> {
                    if (rowSet.iterator().hasNext()) {
                        Row row = rowSet.iterator().next();
                        JsonObject document = new JsonObject()
                                .put("id", row.getString("id"))
                                .put("title", row.getString("title"))
                                .put("content", row.getString("content"));
                        promise.complete(document);
                    } else {
                        promise.complete(new JsonObject().put("error", "Document not found"));
                    }
                })
                .onFailure(promise::fail);
        return promise;
    }

    /**
     * 从 SQLite FTS5 虚拟表搜索相关文档内容。
     *
     * @param query 用户查询
     * @return 包含相关文档内容的 JsonArray (每个元素是文档的 content 字段)
     */
    private Promise<JsonArray> searchDocuments(String query) {
        Promise<JsonArray> promise = Promise.promise();
        // 1. 从 FTS5 表进行全文搜索，获取匹配的文档 ID
        sqlitePool.preparedQuery("SELECT id FROM documents_fts WHERE documents_fts MATCH ? LIMIT 3")
                .execute(Tuple.of(query))
                .compose(rowSet -> {
                    List<String> matchingIds = new ArrayList<>();
                    for (Row row : rowSet) {
                        matchingIds.add(row.getString("id"));
                    }

                    if (matchingIds.isEmpty()) {
                        return Future.succeededFuture(new JsonArray()); // 没有找到匹配文档
                    }

                    // 2. 根据 FTS5 搜索到的 ID，从主表获取完整的文档内容
                    // 构建一个动态的 IN 子句
                    String placeholders = String.join(",", java.util.Collections.nCopies(matchingIds.size(), "?"));
                    return sqlitePool.preparedQuery(String.format("SELECT content FROM documents WHERE id IN (%s)", placeholders))
                            .execute(Tuple.from(matchingIds))
                            .map(contentRowSet -> {
                                JsonArray retrievedContext = new JsonArray();
                                for (Row row : contentRowSet) {
                                    retrievedContext.add(row.getString("content"));
                                }
                                LOGGER.info("SQLite FTS5 search for query '{}' returned {} hits.", query, retrievedContext.size());
                                return retrievedContext;
                            });
                })
                .onSuccess(promise::complete)
                .onFailure(throwable -> {
                    LOGGER.error("Failed to search documents with FTS5: {}", throwable.getMessage());
                    promise.fail("Failed to search documents with FTS5: " + throwable.getMessage());
                });
        return promise;
    }

    @Override
    public void stop(Promise<Void> stopPromise) {
        if (sqlitePool != null) {
            sqlitePool.close()
                    .onComplete(ar -> {
                        if (ar.succeeded()) {
                            LOGGER.info("SQLite connection pool closed.");
                        } else {
                            LOGGER.error("Failed to close SQLite connection pool", ar.cause());
                        }
                        stopPromise.complete();
                    });
        } else {
            stopPromise.complete();
        }
    }
}